package com.monkeyboy.mytest.config;

import java.util.UUID;

import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.amqp.support.ConsumerTagStrategy;
import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import com.monkeyboy.mytest.adapter.MessageDelegate;
import com.monkeyboy.mytest.convert.ImageMessageConverter;
import com.monkeyboy.mytest.convert.PDFMessageConverter;
import com.monkeyboy.mytest.convert.TextMessageConverter;

/**
 * 作用： springboot整合rabbitMq
 * 
 * @author Gavin
 * @time:2019年1月14日
 */
@Configuration
@ComponentScan({ "com.monkeyboy.mytest.*" })
public class RabbitMQConfig {
	/**
	 * 作用： 获取rabbitMq的连接工厂
	 * 
	 * @Author:Gavin
	 * @time:2019年1月14日
	 * @return
	 */
	@Bean
	public ConnectionFactory connectionFactory() {
		CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
		connectionFactory.setAddresses("127.0.0.1");
		connectionFactory.setUsername("Gavin");
		connectionFactory.setPassword("123456");
		connectionFactory.setVirtualHost("/myproject");
		return connectionFactory;
	}

	/**
	 * 作用： 获取rabbitAdmin对象， 主要用户声明交换机，队列，和绑定他们之间的关系
	 * 
	 * @Author:Gavin
	 * @time:2019年1月14日
	 * @param connectionFactory要和上面的方法名一样才行，不然会报空指针错误
	 * @return
	 */
	@Bean
	public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
		RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
		rabbitAdmin.setAutoStartup(true);
		return rabbitAdmin;
	}

	/**
	 * 作用： rabbitMq的消息模板
	 * 
	 * @Author:Gavin
	 * @time:2019年1月14日
	 * @param connectFactory
	 * @return
	 */
	@Bean
	public RabbitTemplate rabbitTemplate(ConnectionFactory connectFactory) {
		RabbitTemplate rabbitTemplate = new RabbitTemplate(connectFactory);
		return rabbitTemplate;
	}

	/**
	 * 作用： 声明一个交换机
	 * 
	 * @Author:Gavin
	 * @time:2019年1月14日
	 * @return
	 */
	@Bean
	public TopicExchange exchange001() {
		return new TopicExchange("topic001", true, false);
	}

	/**
	 * 作用： 声明一个队列
	 * 
	 * @Author:Gavin
	 * @time:2019年1月14日
	 * @return
	 */
	@Bean
	public Queue queue001() {
		return new Queue("queue001", true);
	}

	/**
	 * 作用： 绑定queue001队列到exchange001交换机上
	 * 
	 * @Author:Gavin
	 * @time:2019年1月14日
	 * @return
	 */
	@Bean
	public Binding binding001() {
		return BindingBuilder.bind(queue001()).to(exchange001()).with("spring.*");
	}

	/**
	 * rabbitMq的简单消息监听容器和消息监听适配器 作用： 相当于一个消费者监听容器，有消息就会进行消费
	 * 
	 * @Author:Gavin
	 * @time:2019年1月14日
	 * @param connectFactory
	 * @return
	 */
	@Bean
	public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectFactory) {
		SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectFactory);
		container.setQueues(queue001());// 设置监听的队列，可以设置多个，逗号分隔
		container.setConcurrentConsumers(1);// 设置需要有多少个消费者（和监听的队列数量最好一致）
		container.setMaxConcurrentConsumers(5);// 设置最多有多少个消费者
		container.setDefaultRequeueRejected(false);// 是否重回队列
		container.setAcknowledgeMode(AcknowledgeMode.MANUAL);// 设置自动签收为自动
		container.setConsumerTagStrategy(new ConsumerTagStrategy() {
			// 可以设置tag标签，为每一个队列的消费者
			@Override
			public String createConsumerTag(String queue) {
				return queue + "_" + UUID.randomUUID().toString();
			}
		});

		// 第一种消费消息方式 简单消息监听器的使用
		container.setMessageListener(new ChannelAwareMessageListener() {

			@Override
			public void onMessage(Message message, com.rabbitmq.client.Channel channel) throws Exception {// 就是监听每一条消息并进行处理
				String msg = new String(message.getBody());
				System.err.println("-------消费者：" + msg);
				System.err.println(channel);
				// channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,
				// false);不成功的签收
				channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);// 手工签收

			}
		});

		// 第二种消费方式(适配器):

		/*MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
		adapter.setDefaultListenerMethod("consumeMessage");// 如果不设置的话就会走MessageDelegate类中的handleMessage方法，可以看看源代码，比较简单
		adapter.setMessageConverter(new TextMessageConverter());
		container.setMessageListener(adapter);*/

		/**
		 * 第三种消费模式（适配器模式）：我们的队列名称和方法名称也可以进行--匹配
		 */

		/*MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
		Map<String, String> queueOrTagToMethodName = new HashMap<String, String>();
		queueOrTagToMethodName.put("queue001", "consumeMessageForSelf");// 指定队列名为queue001的给哪个方法（这儿可以添加多个）
		adapter.setQueueOrTagToMethodName(queueOrTagToMethodName);
		adapter.setMessageConverter(new TextMessageConverter());
		container.setMessageListener(adapter);*/

		// 1.1支持JSON格式的转换器
		
		  /*MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
		  adapter.setDefaultListenerMethod("consumeMessageForJson");
		  Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
		  adapter.setMessageConverter(jackson2JsonMessageConverter);
		 container.setMessageListener(adapter);*/
		 

		// 1.2 DefaultJackson2JavaTypeMapper & Jackson2JsonMessageConverter 支持java对象转换

		
		  /*MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
		   adapter.setDefaultListenerMethod("consumeMessage");
		  
		  Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
		  
		  DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper();// 会识别Header参数中的__TypeId__的值
		  jackson2JsonMessageConverter.setJavaTypeMapper(javaTypeMapper);
		  javaTypeMapper.setTrustedPackages("com.monkeyboy.mytest.entity");// 要设置一个可信赖的包位置，可以设为（*）表示信赖所有,也可以设置多个，逗号分隔
		  adapter.setMessageConverter(jackson2JsonMessageConverter);
		  container.setMessageListener(adapter);*/
		 

		// 1.3 DefaultJackson2JavaTypeMapper & Jackson2JsonMessageConverter
		// 支持java对象多映射转换

		
		/*  MessageListenerAdapter adapter = new MessageListenerAdapter(new
		  MessageDelegate()); adapter.setDefaultListenerMethod("consumeMessage");
		  Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
		  DefaultJackson2JavaTypeMapper javaTypeMapper= new DefaultJackson2JavaTypeMapper();
		  javaTypeMapper.setTrustedPackages("com.monkeyboy.mytest.entity"); 
		  Map<String,Class<?>> idClassMapping = new HashMap<String, Class<?>>();
		  idClassMapping.put("order", com.monkeyboy.mytest.entity.Order.class);
		  idClassMapping.put("packaged",com.monkeyboy.mytest.entity.Packaged.class);
		  
		  javaTypeMapper.setIdClassMapping(idClassMapping);
		  
		  jackson2JsonMessageConverter.setJavaTypeMapper(javaTypeMapper);
		  adapter.setMessageConverter(jackson2JsonMessageConverter);
		  container.setMessageListener(adapter);*/
		 

		// 1.4 ext convert
		  MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate()); 
		  adapter.setDefaultListenerMethod("consumeMessage");
		  // 全局的转换器:
		  ContentTypeDelegatingMessageConverter convert = new ContentTypeDelegatingMessageConverter();
		  
		  TextMessageConverter textConvert = new TextMessageConverter();
		  convert.addDelegate("text", textConvert); 
		  convert.addDelegate("html/text",textConvert);
		  convert.addDelegate("xml/text", textConvert);
		  convert.addDelegate("text/plain", textConvert);
		  
		  Jackson2JsonMessageConverter jsonConvert = new Jackson2JsonMessageConverter();
		  convert.addDelegate("json", jsonConvert);
		  convert.addDelegate("application/json", jsonConvert);
		  
		  ImageMessageConverter imageConverter = new ImageMessageConverter();
		  convert.addDelegate("image/jpg", imageConverter);
		  convert.addDelegate("image", imageConverter);
		  
		  PDFMessageConverter pdfConverter = new PDFMessageConverter();
		  convert.addDelegate("application/pdf", pdfConverter);
		  
		  adapter.setMessageConverter(convert);
		  
		  container.setMessageListener(adapter);
		 

		return container;
	}

}
